﻿
using FaissOperation.Interface;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace FaissOperation
{
    /// <summary>
    /// 向量知识库
    /// </summary>
    public class GeneralConverter
    {
        /// <summary>
        /// 序列化向量集合数据，采用GZip压缩后转换为BASE64字符串
        /// </summary>
        /// <param name="data">集合数据</param>
        /// <returns>BASE64数据</returns>
        public static string ToZipBase64(PlainCollectionData data)
        {
            if (data == null)
            {
                return string.Empty;
            }

            // 处理原始数据
            using var ms = new MemoryStream();
            using var bw = new BinaryWriter(ms);

            // 写头信息
            bw.Write((int)data.MetricType);
            bw.Write(data.Dimension);
            bw.Write(data.NormalizeOnAdd);

            // 写向量个数
            bw.Write(data.Ids.Count);

            // 写 ID
            foreach (var id in data.Ids)
                bw.Write(id);

            // 写 Vectors
            foreach (var vec in data.Vectors)
            {
                foreach (var f in vec)
                    bw.Write(f);
            }

            bw.Flush();

            var bytes = ms.ToArray();

            // 压缩数据
            using var ms2 = new MemoryStream();
            using (var gzip = new GZipStream(ms2, CompressionLevel.Fastest))
                gzip.Write(bytes, 0, bytes.Length);

            return Convert.ToBase64String(ms2.ToArray());

        }

        /// <summary>
        /// 反序列化向量集合数据
        /// </summary>
        /// <param name="text">GZip压缩后的BASE64数据</param>
        /// <returns>集合数据</returns>
        public static PlainCollectionData ToCollectionData(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return new PlainCollectionData();
            }

            var compressed = Convert.FromBase64String(text);
            using var ms1 = new MemoryStream(compressed);
            using var gzip = new GZipStream(ms1, CompressionMode.Decompress);
            using var outStream = new MemoryStream();
            gzip.CopyTo(outStream);

            var bytes = outStream.ToArray();

            using var ms = new MemoryStream(bytes);
            using var br = new BinaryReader(ms);

            var data = new PlainCollectionData
            {
                MetricType = (MetricType)br.ReadInt32(),
                Dimension = br.ReadInt32(),
                NormalizeOnAdd = br.ReadBoolean()
            };

            int count = br.ReadInt32();

            data.Ids = new List<int>(count);
            data.Vectors = new List<float[]>(count);

            for (int i = 0; i < count; i++)
                data.Ids.Add(br.ReadInt32());

            for (int i = 0; i < count; i++)
            {
                if (data.Dimension != br.BaseStream.Length)
                {
                    throw new Exception($"向量数据的长度为 {br.BaseStream.Length} ，与集合的维度数量 {data.Dimension} 不一致。");
                }

                var vec = new float[data.Dimension];
                for (int j = 0; j < data.Dimension; j++)
                    vec[j] = br.ReadSingle();
                data.Vectors.Add(vec);
            }

            return data;
        }

        /// <summary>
        /// 将对象转换为整数ID集合
        /// </summary>
        /// <param name="source">原始对象，支持多种类型</param>
        /// <returns>ID数组</returns>
        public static IEnumerable<int> ToIDs(object source)
        {
            if (source == null)
            {
                return [];
            }

            if (source is IEnumerable<int>)
            {
                return (IEnumerable<int>)source;
            }

            if (source is IEnumerable enumerable)
            {
                return [.. enumerable.Cast<object>().Select(x => (x is int) ? (int)x : int.Parse(x.ToString()))];
            }

            if (source is ArrayList arr)
            {
                return [.. arr.ToArray().Select(x => (x is int) ? (int)x : int.Parse(x.ToString()))];
            }

            if (source is IList list)
            {
                return [.. list.Cast<object>().Select(x => (x is int) ? (int)x : int.Parse(x.ToString()))];
            }

            if (source is JsonArray jsonArray)
            {
                return [.. jsonArray.Select(x => (x is JsonValue jsonValue) ? (int)jsonValue : int.Parse(x.ToString()))];
            }

            var sourceString = source.ToString();

            sourceString = sourceString.Trim('[', ']'); // 去除方括号   
            sourceString = sourceString.Replace(" ", ""); // 去除空格
            sourceString = sourceString.Replace("\r\n", ""); // 去除换行符

            var arrS = sourceString.Split(',');
            List<int> result = new();
            for (int i = 0; i < arrS.Length; i++)
            {
                int v = -1;

                if (int.TryParse(arrS[i], out v))
                {
                    result.Add(v);
                }
            }

            return result;
        }

        /// <summary>
        /// 转换为ID和向量的元组集合
        /// </summary>
        /// <param name="json">特定格式的JSON字符串，形如[{\"id\":1,\"embedding\":[0.112,0.9871,...]},{\"id\":2,\"embedding\":[0.311,0.561,...]}]</param>
        /// <returns>元组集合</returns>
        /// <exception cref="Exception">JSON反序列化失败</exception>
        public static IList<(int Id, float[] Vector)> ToVectors(string json)
        {

            // 处理JSON字符串，形如：插入集合的向量数组，形如[{\"id\":1,\"embedding\":[0.112,0.9871,...]},{\"id\":2,\"embedding\":[0.311,0.561,...]}]
            if (string.IsNullOrEmpty(json))
                return [];

            try
            {
                var jsonArray = JsonSerializer.Deserialize<JsonArray>(json);
                if (jsonArray == null)
                    return [];
                return jsonArray.Select(item =>
                {
                    if (item is JsonObject obj && obj.TryGetPropertyValue("id", out var idValue) && obj.TryGetPropertyValue("embedding", out var embeddingValue))
                    {
                        int id = idValue.GetValue<int>();
                        float[] embedding = ToVector(embeddingValue.ToString());
                        return (id, embedding);
                    }
                    return default((int, float[]));
                }).Where(x => x.Item2 != null).ToList();
            }
            catch (Exception ex)
            {
                throw new Exception($"解析JSON失败: {ex.Message}");
            }

        }

        public static float[][] To2DVectors(object source)
        {

            if (source == null)
            {
                return [];
            }

            if (source is float[][] arrFloat2D)
            {
                return arrFloat2D; // 如果已经是二维浮点数组，直接返回
            }

            if (source is IEnumerable enumerable)
            {
                return [.. enumerable.Cast<object>().Select(x => (x is float[]) ? (float[])x : ToVector(x.ToString()))];
            }

            if (source is ArrayList arr)
            {
                return [.. arr.ToArray().Select(x => (x is float[]) ? (float[])x : ToVector(x.ToString()))];
            }

            if (source is IList list)
            {
                return [.. list.Cast<object>().Select(x => (x is float[]) ? (float[])x : ToVector(x.ToString()))];
            }

            if (source is JsonArray jsonArray)
            {
                return [.. jsonArray.Select(x => (x is JsonValue jsonValue) ? ToVector(jsonValue.ToString()) : ToVector(x.ToString()))];
            }

            var sourceString = source.ToString();

            sourceString = sourceString.Trim('[', ']'); // 去除方括号   
            sourceString = sourceString.Replace("\r\n", ""); // 去除换行符

            var arrS = sourceString.Split(new string[] { "],[" }, StringSplitOptions.RemoveEmptyEntries);
            List<float[]> result = new();
            for (int i = 0; i < arrS.Length; i++)
            {
                var vec = ToVector(arrS[i]);
                if (vec != null)
                    result.Add(vec);
            }

            return result.ToArray();
        }

        /// <summary>
        /// 将字符串形式的向量转换为浮点数组
        /// </summary>
        /// <param name="embeddingString">以逗号分隔的的字符串</param>
        /// <returns>浮点数组</returns>
        public static float[] ToVector(string embeddingString)
        {
            if (string.IsNullOrEmpty(embeddingString))
                return null;

            embeddingString = embeddingString.Trim('[', ']'); // 去除方括号   
            embeddingString = embeddingString.Replace(" ", ""); // 去除空格
            embeddingString = embeddingString.Replace("\r\n", ""); // 去除换行符

            var arr = embeddingString.Split(',');
            float[] result = new float[arr.Length];
            for (int i = 0; i < arr.Length; i++)
            {
                float v = -1;

                if (float.TryParse(arr[i], out v))
                {
                    result[i] = v;
                }
            }
            return result;
        }

        /// <summary>
        /// 将对象转换为浮点数组
        /// </summary>
        /// <param name="target">原始对象，支持多种类型</param>
        /// <returns>浮点数组</returns>
        public static float[] ToVector(object target)
        {
            if (target == null)
            {
                return [];
            }

            if (target is string embedding)
            {
                return ToVector(embedding);
            }

            if (target is ArrayList arr)
            {
                return [.. arr.ToArray().Select(x => (x is float) ? (float)x : float.Parse(x.ToString()))]; // 其他都需要转换为浮点数
            }

            if (target is IEnumerable enumerable)
            {
                return [.. enumerable.Cast<object>().Select(x => (x is float) ? (float)x : float.Parse(x.ToString()))]; // 其他都需要转换为浮点数
            }

            if (target is float[] arrFloat)
            {
                return arrFloat; // 如果已经是浮点数组，直接返回
            }

            if (target is double[] arrDouble)
            {
                return arrDouble.Select(x => (float)x).ToArray(); // 如果是双精度数组，转换为浮点数组
            }

            if (target is IList list)
            {
                return [.. list.Cast<object>().Select(x => (x is float) ? (float)x : float.Parse(x.ToString()))]; // 其他都需要转换为浮点数
            }

            if (target is JsonArray jsonArray)
            {
                return [.. jsonArray.Select(x => (x is JsonValue jsonValue) ? (float)jsonValue : float.Parse(x.ToString()))]; // 如果是JsonArray类型，转换为浮点数组
            }

            return [];

        }


    }
}
